package wall

import (
	"encoding/binary"
	"fmt"
	"net"

	"gitee.com/haodreams/libs/sock"
)

//发送文件不合并

const MaxSize = 64*1024 - 6

type Writer struct {
	ackChar   byte   //确认字符
	timeoutMs int64  //超时时间,单位毫秒
	head      []byte //包头2字节
	withWall  bool   //是否开启隔离
	conn      *net.TCPConn
}

func NewWriter(conn *net.TCPConn) *Writer {
	m := new(Writer)
	m.timeoutMs = 30 * 1000
	m.Setup().SetConn(conn)
	return m
}

func (m *Writer) Setup() *Writer {
	m.head = make([]byte, 2)
	return m
}

func (m *Writer) SetAckChar(ackChar byte) *Writer {
	m.ackChar = ackChar
	m.withWall = true
	return m
}

func (m *Writer) SetTimeout(timeoutMs int64) *Writer {
	m.timeoutMs = min(max(timeoutMs, 1000), 120*1000)
	return m
}

func (m *Writer) SetConn(conn *net.TCPConn) *Writer {
	m.conn = conn
	return m
}

func (m *Writer) Write(header, buf []byte) (n int, err error) {
	if len(buf) > MaxSize {
		err = fmt.Errorf("数据长度不能超过64k")
		return
	}

	//写入数据长度
	binary.BigEndian.PutUint16(m.head, uint16(len(header)+len(buf)))
	n, err = m.conn.Write(m.head)
	if err != nil {
		return
	}

	if len(header) > 0 {
		n, err = m.conn.Write(header)
		if err != nil {
			return
		}
	}
	//写入数据
	n, err = m.conn.Write(buf)
	if err != nil {
		return
	}

	if m.withWall {
		_, err := sock.ReadTimeoutMs(m.conn, m.head[:1], int(m.timeoutMs))
		if err != nil {
			return n, err
		}
		if m.head[0] != m.ackChar {
			err = fmt.Errorf("确认字符错误")
			return n, err
		}
	}
	return
}

func (m *Writer) WritePacket(conn *net.TCPConn, buf []byte) (n int, err error) {
	l := len(buf)
	n1 := 0
	head := make([]byte, 4) //4字节数据长度
	binary.BigEndian.PutUint32(head, uint32(len(buf)))
	for i := 0; i < l; i += MaxSize {
		end := min(i+MaxSize, l)
		if i == 0 {
			n1, err = m.Write(head, buf[i:end])
		} else {
			n1, err = m.Write(nil, buf[i:end])
		}

		if err != nil {
			return
		}
		n += n1
	}
	if n != l {
		panic("assert error")
	}
	return
}

// 没有隔离器的情况
func Write(conn *net.TCPConn, header []byte, buf []byte) (n int, err error) {
	if len(buf) > MaxSize {
		err = fmt.Errorf("数据长度不能超过64k")
		return
	}
	head := make([]byte, 2)
	binary.BigEndian.PutUint16(head, uint16(len(header)+len(buf)))
	n, err = conn.Write(head)
	if err != nil {
		return
	}
	if len(header) > 0 {
		n, err = conn.Write(header)
		if err != nil {
			return
		}
	}
	n, err = conn.Write(buf)
	if err != nil {
		return
	}
	return
}

func WritePacket(conn *net.TCPConn, buf []byte) (n int, err error) {
	l := len(buf)
	n1 := 0
	head := make([]byte, 4)
	binary.BigEndian.PutUint32(head, uint32(len(buf)))
	for i := 0; i < l; i += MaxSize {
		end := min(i+MaxSize, l)
		if i == 0 {
			n1, err = Write(conn, head, buf[i:end])

		} else {
			n1, err = Write(conn, nil, buf[i:end])
		}

		if err != nil {
			return
		}
		n += n1
	}
	return
}
